﻿using System;
using System.Net;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

public class NetworkConnection : IDisposable
{
    private string networkName;
    private const int TimeoutMilliseconds = 3000; // 15秒超时

    public NetworkConnection(string networkName, NetworkCredential credentials)
    {
        this.networkName = networkName;
        ConnectWithTimeout(networkName, credentials);
    }

    private void ConnectWithTimeout(string networkName, NetworkCredential credentials)
    {
        var connectTask = Task.Run(() => Connect(networkName, credentials));
        if (!connectTask.Wait(TimeoutMilliseconds))
        {
            throw new TimeoutException("连接共享文件夹超时");
        }
    }

    private void Connect(string networkName, NetworkCredential credentials)
    {
        var netResource = new NetResource
        {
            Scope = ResourceScope.GlobalNetwork,
            Type = ResourceType.Disk,
            DisplayType = ResourceDisplaytype.Share,
            RemoteName = networkName
        };

        int result = WNetAddConnection2(netResource, credentials.Password, credentials.UserName, 0);
        if (result != 0)
        {
            throw new IOException($"无法连接到共享文件夹，错误码：{result}");
        }
    }

    public void Dispose()
    {
        WNetCancelConnection2(networkName, 0, true);
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(
        NetResource netResource,
        string password,
        string username,
        int flags
    );

    [DllImport("mpr.dll")]
    private static extern int WNetCancelConnection2(
        string name,
        int flags,
        bool force
    );

    [StructLayout(LayoutKind.Sequential)]
    private class NetResource
    {
        public ResourceScope Scope;
        public ResourceType Type;
        public ResourceDisplaytype DisplayType;
        public int Usage;
        public string LocalName;
        public string RemoteName;
        public string Comment;
        public string Provider;
    }

    private enum ResourceScope : int
    {
        Connected = 1,
        GlobalNetwork,
        Remembered,
        Recent,
        Context
    }

    private enum ResourceType : int
    {
        Any = 0,
        Disk = 1,
        Print = 2
    }

    private enum ResourceDisplaytype : int
    {
        Generic = 0,
        Domain = 1,
        Server = 2,
        Share = 3,
        File = 4,
        Group = 5
    }
}